%{
	#include "funcoes.h"

	extern FILE *yyin;

	int main(int argc, char **argv) {

    inicializa_tabela_simb(tabela_simbolos);
    inicializa_tabela_res(tabela_pal_res);
		inicializa_auxiliares();
	
		if (argc == 2) {
			yyin = fopen(argv[1], "r");
			add_inst("INPP");
			yyparse();
			if(num_erros == 0)
				add_inst("PARA");
			
			print_errors();
			//print_tab_simb(tabela_simbolos);
			print_insts("codigo.txt");			
		} else 
			printf("Paramentros de entrada incorretos\n");
		
		return 0;
	}

%}

%union YYSTYPE{
	int int_valor;
	float real_valor;
	char* nome;
	int tipo;
	struct exp {
		int int_valor;
		float real_valor;
		int tipo;
		char op;
	} exp;
	char op;
	char* relacao;
	int condicao;
}

%token BGIN
%token PROGRAM
%token END
%token CONST
%token VAR
%token TIPO_REAL
%token TIPO_INTEGER
%token PROCEDURE
%token ELSE
%token READLN
%token WRITELN
%token WHILE
%token DO
%token REPEAT
%token UNTIL
%token IF
%token THEN

%token PVIRG
%token PONTO
%token VIRG
%token APAR
%token FPAR
%token DPONTOS
%token ATRIB
%token IGUAL
%token DIFER
%token MAIOR_IGUAL
%token MENOR_IGUAL
%token MAIOR
%token MENOR

%token SOMA
%token SUB
%token MULT
%token DIV

%token <nome> IDENT
%token <tipo> REAL
%token <tipo> INT
%token <int_valor> NUM_INT
%token <real_valor> NUM_REAL

// tipos dos não terminais:
%type <exp> numero
%type <exp> fator
%type <exp> mais_fatores
%type <exp> termo
%type <exp> outros_termos
%type <exp> expressao
%type <exp> cmd2
%type <relacao> relacao
%type <condicao> condicao
%type <op> op_mul
%type <op> op_ad
%type <op> op_un
%type <nome> variaveis
%type <tipo> tipo_var

%start programa

%%
programa:
                PROGRAM IDENT PVIRG corpo PONTO {
					pos = busca_simb(tabela_simbolos, $2, hash($2));
                        if(pos != -1)
                                adderror(SEMANTICO, "ID utilizado na declaracao do programa.", linhas);
                        else
                                insere_simb(tabela_simbolos, $2, 4, escopo, 0, 0);
					}
                |
                error PVIRG {adderror(SINTATICO,"Problema na declaracao do programa - 'program ID' esperado.", linhas); yyclearin; yyerrok;} corpo PONTO
                |
                PROGRAM IDENT error {adderror(SINTATICO,"Problema na declaracao do programa - ';'  esperado.", linhas); yyclearin;} corpo PONTO
                |
                PROGRAM IDENT {adderror(SINTATICO,"Problema na declaracao do programa - ';' esquecido.", linhas);} corpo PONTO
                |
                PROGRAM IDENT PVIRG error PONTO{adderror(SINTATICO,"Problema geral na declaracao do corpo.", linhas); yyclearin; yyerrok;}
                |
                PROGRAM IDENT PVIRG corpo error {adderror(SINTATICO,"Problema na declaracao do programa '.' esperado.", linhas); yyclearin; yyerrok;}
                ;

corpo:
                dc BGIN comandos END
                |
                error BGIN {adderror(SINTATICO,"Problema geral nas declaracoes.", linhas); yyclearin;} comandos END {yyerrok;}
                |
                dc error {adderror(SINTATICO,"Problema na declaracao do corpo 'begin' esperado.", linhas); yyclearin;} comandos END {yyerrok;}
                |
                dc {adderror(SINTATICO,"Problema na declaracao do corpo 'begin' esquecido.", linhas);} comandos END {yyerrok;}
                |
                dc BGIN error END {adderror(SINTATICO,"Problema geral na declaracao de comandos.", linhas); yyclearin; yyerrok;}
                |
                dc BGIN comandos error {adderror(SINTATICO,"Problema na declaracao do corpo 'end' esperado.", linhas); yyclearin;}
                ;

dc:     
                dc_c dc_v {escopo++;} dc_p  {
									escopo = 0;
									comando = 1;
									if(current_proc_inst != -1) {
										update_instv(current_proc_inst, num_inst+1);
										current_proc_inst = -1;
									}									
								}
                ;

dc_c:
                |
                CONST IDENT IGUAL numero PVIRG {
                        pos = busca_simb(tabela_simbolos, $2, hash($2));
                        if(pos != -1)
                                adderror(SEMANTICO, "ID ja declarado anteriormente.", linhas);
                        else
                                {
                                insere_simb(tabela_simbolos, $2, $4.tipo, escopo, $4.real_valor, $4.int_valor);
                                add_instv("ALME", 1);
                                if($4.tipo == FLOAT)
                                        add_instv("CRVL", $4.real_valor);
                                else
                                        add_instv("CRVL", $4.int_valor);
                                pos = busca_simb(tabela_simbolos, $2, hash($2));
                                add_instv("ARMZ", pos); 
                                } 
                        } dc_c
                |
                error numero {adderror(SINTATICO,"Problema na declaracao de constante - 'const ID =' esperado.", linhas);} PVIRG {yyerrok;} dc_c 
                |
                error BGIN {adderror(SINTATICO,"Problema na inicializacao da declaracao - 'var' ou 'procedure' esperado (Compilacao ABORTADA).", linhas); YYABORT;}
                |
                error END {adderror(SINTATICO,"Problema na inicializacao do corpo - 'begin' faltando (Compilacao ABORTADA).", linhas); YYABORT;}
                |
                CONST IDENT IGUAL error PVIRG{adderror(SINTATICO,"Problema na declaracao de numero - numero inteiro ou float esperado.", linhas); yyclearin; yyerrok;} dc_c
                |
                CONST IDENT IGUAL numero error {adderror(SINTATICO,"Problema na declaracao de constante - ';' esperado.", linhas); yyclearin; yyerrok;} dc_c
                |
                CONST IDENT IGUAL numero {adderror(SINTATICO,"Problema na declaracao de constante - ';' esquecido.", linhas); yyerrok;} dc_c
                ;

dc_v:   
                |       
                VAR variaveis DPONTOS tipo_var PVIRG {
                        int i;
                        for(i=0; i<750; i++)
                                {
                                if(tabela_simbolos[i].escopo == 100 || tabela_simbolos[i].escopo == 200)
                                        {
                                        tabela_simbolos[i].escopo = escopo;
                                        tabela_simbolos[i].tipo = $4;
                                        }
                                }       
                        } dc_v
                |
                error DPONTOS {adderror(SINTATICO,"Problema na declaracao de variavel - 'var' esperado.", linhas);} tipo_var PVIRG {yyerrok;} dc_v 
                |
                error BGIN {adderror(SINTATICO,"Problema na inicializacao da declaracao - 'procedure' esperado (Compilacao ABORTADA).", linhas); YYABORT;}
                |
                error END {adderror(SINTATICO,"Problema na inicializacao do corpo - 'begin' faltando (Compilacao ABORTADA).", linhas); YYABORT;}
                |
                VAR error DPONTOS {adderror(SINTATICO,"Problema na declaracao de variavel - IDs com problema.", linhas);} tipo_var PVIRG {yyerrok;} dc_v 
                |
                VAR variaveis error {adderror(SINTATICO,"Problema na declaracao de variavel - ':' esperado.", linhas); yyclearin;} tipo_var PVIRG {yyerrok;} dc_v 
                |
                VAR variaveis tipo_var {adderror(SINTATICO,"Problema na declaracao de variavel - ':' esquecido.", linhas);} PVIRG {yyerrok;} dc_v 
                |
                VAR variaveis DPONTOS error PVIRG {adderror(SINTATICO,"Problema na declaracao de variavel - Tipo de IDs com problema.", linhas); yyerrok;} dc_v 
                |
                VAR variaveis DPONTOS tipo_var error {adderror(SINTATICO,"Problema na declaracao de variavel - ';' esperado.", linhas); yyclearin; yyerrok;} dc_v
                |
                VAR variaveis DPONTOS tipo_var {adderror(SINTATICO,"Problema na declaracao de variavel - ';' esquecido.", linhas); yyerrok;} dc_v
                ;

tipo_var:
                REAL    { $$ = $1; }
                |
                INT     { $$ = $1; }
                ;

variaveis:
                IDENT   {
                        if(busca_simb_escopo(tabela_simbolos, $1, hash($1), escopo) != -1 && comando == 0)
                                {
                                adderror(SEMANTICO, "ID ja declarado anteriormente.", linhas);
                                }
                    else if(comando == 0){
                            if(escopo > 0) {
                                    insere_simb(tabela_simbolos, $1, INDEFINIDO, 200, 0, 0);
                                    cur_proc.args[cur_proc.n_arg] = busca_simb_escopo(tabela_simbolos, $1, hash($1), 200);
                                    cur_proc.n_arg++;
                            } else {
                                    insere_simb(tabela_simbolos, $1, INDEFINIDO, 100, 0, 0);
																		add_instv("ALME", 1);
                            }
                    }
                        else
                                {
                                pos = busca_simb_escopo(tabela_simbolos, $1, hash($1), escopo);
                                if(pos == -1)
                                        adderror(SEMANTICO, "ID nao declarado.", linhas);
                                else if(tabela_simbolos[pos].tipo == FLOAT)
                                        {
                                        var_pos[var_real+var_int] = pos;
                                        var_real++;
                                        }
                                else
                                        {
                                        var_pos[var_real+var_int] = pos;
                                        var_int++;
                                        }
                                }
                        } mais_var {
                                cur_proc.args[cur_proc.n_arg] = -1;
                        }
                ;

mais_var: 
                |
                VIRG variaveis
                ;

dc_p:
                |
                PROCEDURE IDENT parametros PVIRG {
                        if(busca_simb(tabela_simbolos, $2, hash($2)) != -1)
                                adderror(SEMANTICO, "ID ja declarado anteriormente.", linhas);
                        else {
                                insere_simb(tabela_simbolos, $2, RESERVADO, escopo-1, 0, 0);
																current_proc_inst = add_instv("DESVI", 0);
                                int i;
                                for(i=0; i <= cur_proc.n_arg ; i++) {
                                        tabela_simbolos[busca_simb(tabela_simbolos, $2, hash($2))].proc_args[i] = cur_proc.args[i];
																				add_instv("ALME", 1);
																}
                        }
                        cur_proc.n_arg = 0;
                } corpo_p {comando = 0;}dc_p
                |
                error parametros {adderror(SINTATICO,"Problema na declaracao de parametro - 'procedure ID' esperado.", linhas); yyerrok;} PVIRG corpo_p dc_p
                |
                error END {adderror(SINTATICO,"Problema na inicializacao do corpo - 'begin' faltando. (Compilacao ABORTADA)", linhas); YYABORT;}
                |
                PROCEDURE IDENT error PVIRG {adderror(SINTATICO,"Problema geral em parametros.", linhas); yyerrok;} corpo_p dc_p 
                |
                PROCEDURE IDENT parametros error {adderror(SINTATICO,"Problema na declaracao de parametro - ';' esperado..", linhas); yyclearin;} corpo_p dc_p 
                |
                PROCEDURE IDENT parametros {adderror(SINTATICO,"Problema na declaracao de parametro - ';' esquecido.", linhas); yyerrok;} corpo_p dc_p 
                |
                PROCEDURE IDENT parametros PVIRG error{adderror(SINTATICO,"Problema geral no corpo do parametro.", linhas); yyerrok;} dc_p 
                ;

parametros:     
                |
                APAR lista_par FPAR
                |
                error {adderror(SINTATICO,"Problema nos parametros - '(' esperado.", linhas); yyclearin;} lista_par FPAR
                |
                {adderror(SINTATICO,"Problema nos parametros - '(' esquecido.", linhas); } lista_par FPAR
                |
                APAR error FPAR {adderror(SINTATICO,"Problema geral na lista de parametros", linhas); yyerrok;}
                |
                APAR lista_par error {adderror(SINTATICO,"Problema nos parametros - ')' esperado.", linhas); yyclearin;}
                |
                APAR lista_par {adderror(SINTATICO,"Problema nos parametros - ')' esquecido.", linhas); }
                ;

lista_par:      
                variaveis DPONTOS tipo_var {
                        int i;
                        for(i=0; i<750; i++)
                                if(tabela_simbolos[i].escopo == 200) {
                                        tabela_simbolos[i].escopo = escopo;
                                        tabela_simbolos[i].tipo = $3;
                                }
                } mais_par
                |
                error DPONTOS {adderror(SINTATICO,"Problema na lista de parametros - IDs com problema.", linhas); yyerrok;} tipo_var mais_par
                |
                error BGIN {adderror(SINTATICO,"Problema na lista de parametros - ')' faltante (Programa abortado).", linhas); YYABORT;}
                |
                variaveis error {adderror(SINTATICO,"Problema na lista de parametros - ':' esperado.", linhas); yyclearin;} tipo_var mais_par
                |
                variaveis tipo_var {adderror(SINTATICO,"Problema na lista de parametros - ':' esquecido.", linhas); yyerrok;} mais_par
                |
                variaveis DPONTOS error {adderror(SINTATICO,"Problema na lista de parametros - Tipo de IDs com problema.", linhas); yyclearin;} mais_par 
                |
                variaveis DPONTOS {adderror(SINTATICO,"Problema na lista de parametros - Tipo de IDs com problema.", linhas);} mais_par 
                |
                variaveis DPONTOS tipo_var error {adderror(SINTATICO,"Problema na lista de parametros - Erro na separacao de parametros.", linhas); yyclearin; yyerrok;} lista_par
                ;

mais_par:
                |
                PVIRG lista_par
                ;

corpo_p:        
                dc_loc BGIN comandos END PVIRG { add_inst("RTPR"); }
                |
                dc_loc comandos {adderror(SINTATICO,"Problema no corpo do procedimento - 'begin' esquecido.", linhas);} END PVIRG {yyerrok;}
                |
                dc_loc BGIN error END {adderror(SINTATICO,"Problema no corpo do procedimento - Problema geral em comandos.", linhas);} PVIRG {yyerrok;}
                |
                dc_loc BGIN comandos error {adderror(SINTATICO,"Problema no corpo do procedimento - 'end ;' esperado.", linhas);}  {yyerrok;}
                |
                dc_loc BGIN comandos {adderror(SINTATICO,"Problema no corpo do procedimento - 'end;' esquecido.", linhas);}  {yyerrok;}
                ;

dc_loc:
                dc_v { comando = 1; }
                ;

mais_ident:		
                |
                PVIRG argumentos {p--;} 
                ;

lista_arg:
                |
                APAR argumentos FPAR
                ;

argumentos:
                IDENT mais_ident {
					pos = busca_simb_escopo(tabela_simbolos, $1, hash($1), escopo);
					if(pos == -1)
						adderror(SEMANTICO, "ID nao declarado.", linhas);
					else if(p < 0)
						adderror(SEMANTICO, "Quantidade de parametros inconsistente.", linhas);
					else
						{
						if(tabela_simbolos[pos].tipo != tabela_simbolos[tabela_simbolos[id_proc].proc_args[p]].tipo)
							adderror(SEMANTICO, "Passagem de parametros com tipos diferentes.", linhas);
						else
							{
							tabela_simbolos[tabela_simbolos[id_proc].proc_args[p]].int_valor = tabela_simbolos[pos].int_valor;
							tabela_simbolos[tabela_simbolos[id_proc].proc_args[p]].real_valor = tabela_simbolos[pos].real_valor;
							}
						}
					}
                ;

comandos:
                |
                cmd PVIRG comandos
                |
                error PVIRG {adderror(SINTATICO,"Problema em 'comandos' - Comando mal formado.", linhas); yyerrok;} comandos
                |
                cmd error {yyclearin;} comandos {adderror(SINTATICO,"Problema em 'comandos' - ';' esperado.", linhas); yyerrok;}
                |
                cmd comandos {adderror(SINTATICO,"Problema em 'comandos' - ';' esquecido.", linhas); yyerrok;}
                ;

cmd:
                WHILE APAR condicao FPAR { current_inst = add_instv("DSVF", 0); } DO cmd {
                        if($3 == ERRO)
                                {
                                adderror(SEMANTICO, "Condição mal formada no WHILE ", linhas);
                                }
                        else 
                                {
                                add_instv("DSVI", current_inst-3);
                                update_instv(current_inst, num_inst+1);
																current_inst = -1;
                                }
                        }
                |
                WHILE error {yyclearin;} condicao {adderror(SINTATICO,"Problema no WHILE - '(' esperado.", linhas); yyerrok;} FPAR DO cmd
                |
                WHILE condicao {adderror(SINTATICO,"Problema no WHILE - '(' esquecido.", linhas); yyerrok;} FPAR DO cmd
                |
                WHILE APAR FPAR {adderror(SINTATICO,"Problema no WHILE - condicao esquecida.", linhas); yyerrok;} DO cmd
                |
                WHILE APAR condicao error DO {adderror(SINTATICO,"Problema no WHILE - ')' esperado.", linhas); yyerrok;} cmd
                |
                WHILE APAR condicao DO {adderror(SINTATICO,"Problema no WHILE - ')' esquecido.", linhas); yyerrok;} cmd
                |
                WHILE APAR condicao FPAR error {yyclearin;} cmd {adderror(SINTATICO,"Problema no WHILE - 'do' esperado.", linhas); yyerrok;}
                |
                WHILE APAR condicao FPAR cmd {adderror(SINTATICO,"Problema no WHILE - 'do' esquecido.", linhas); yyerrok;}
                |
                WHILE DO {adderror(SINTATICO,"Problema no WHILE - '(condicao)' esquecido.", linhas); yyerrok;} cmd
                |
                READLN APAR variaveis FPAR {
                        if(var_int != 0 && var_real != 0)
                                {
                                adderror(SEMANTICO,"READLN com variaveis de tipos diferentes.", linhas);
                                }
                        else 
                                {
                                int h;
                                for(h = 0; h < var_int + var_real; h++)
                                        {
                                        pos = var_pos[h];
                                        add_inst("LEIT");
                                        add_instv("ARMZ", pos);
                                        }
                                }
                        var_int = 0;
                        var_real = 0;
                        }
                |
                READLN error {yyclearin;} variaveis {adderror(SINTATICO,"Problema no READLN - '(' esperado.", linhas); yyerrok;} FPAR
                |
                READLN variaveis {adderror(SINTATICO,"Problema no READLN - '(' esquecido.", linhas); yyerrok;} FPAR
                |
                READLN APAR error FPAR {adderror(SINTATICO,"Problema no READLN - Erro em variaveis.", linhas); yyerrok;}
                |
                READLN APAR FPAR {adderror(SINTATICO,"Problema no READLN - variaveis esquecidas.", linhas); yyerrok;}
                |
                READLN APAR variaveis error {adderror(SINTATICO,"Problema no READLN - ')' esperado.", linhas); yyclearin; yyerrok;}
                |
                READLN APAR variaveis {adderror(SINTATICO,"Problema no READLN - ')' esquecido.", linhas); yyclearin; yyerrok;}
                |
                WRITELN APAR variaveis FPAR {
                        if(var_int != 0 && var_real != 0)
                                {
                                adderror(SEMANTICO,"WRITELN com variaveis de tipos diferentes.", linhas);
                                }
                        else 
                                {
                                int h;
                                for(h = 0; h < var_int + var_real; h++)
                                        {
                                        pos = var_pos[h];
                                        if(tabela_simbolos[pos].tipo == FLOAT)
                                                add_instv("CRVL", tabela_simbolos[pos].real_valor);
                                        else
                                                add_instv("CRVL", tabela_simbolos[pos].int_valor);
                                        add_inst("IMPR");
                                        }
                                }
                        var_int = 0;
                        var_real = 0;
                        }
                |
                WRITELN error {yyclearin;} variaveis {adderror(SINTATICO,"Problema no WRITELN - '(' esperado.", linhas); yyerrok;} FPAR
                |
                WRITELN variaveis {adderror(SINTATICO,"Problema no WRITELN - '(' esquecido.", linhas); yyerrok;} FPAR
                |
                WRITELN APAR error FPAR {adderror(SINTATICO,"Problema no WRITELN - Erro em variaveis.", linhas); yyerrok;}
                |
                WRITELN APAR FPAR {adderror(SINTATICO,"Problema no WRITELN - variaveis esquecidas.", linhas); yyerrok;}
                |
                WRITELN APAR variaveis error {adderror(SINTATICO,"Problema no WRITELN - ')' esperado.", linhas); yyclearin; yyerrok;}
                |
                WRITELN APAR variaveis {adderror(SINTATICO,"Problema no WRITELN - ')' esquecido.", linhas); yyclearin; yyerrok;}
                |
                IF condicao { current_inst = add_instv("DSVF", 0); } THEN cmd {
                        if($2 == ERRO)
                                {       
                                adderror(SEMANTICO, "Condição mal formada no IF ", linhas);
                                }
                        else 
                                {
                                update_instv(current_inst, num_inst+2);
                                current_inst = add_instv("DSVI", 0);
                                }
                        } pfalsa {
                                update_instv(current_inst, num_inst+1);
																current_inst = -1;
                                }
                |
                IF THEN {adderror(SINTATICO,"Problema no IF - 'condicao' esquecida.", linhas); yyerrok;} cmd pfalsa
                |
                IF condicao error {yyclearin;} cmd {adderror(SINTATICO,"Problema no IF - 'then' esperado.", linhas); yyerrok;} pfalsa
                |
                IF condicao cmd {adderror(SINTATICO,"Problema no IF - 'then' esquecido.", linhas); yyerrok;} pfalsa
                |
                IDENT {
					id_proc = busca_simb_escopo(tabela_simbolos, $1, hash($1), escopo);
						while(tabela_simbolos[id_proc].proc_args[p] != -1)
							p++;
						p--;
					} cmd2 {
			if($3.tipo != ERRO)
				{
				pos = busca_simb_escopo(tabela_simbolos, $1, hash($1), escopo);
				if(pos == -1)
					{
					adderror(SEMANTICO, "ID nao declarado.", linhas);
					}
				else if(tabela_simbolos[pos].tipo == INTEGER && $3.tipo == FLOAT)
					{
					adderror(SEMANTICO, "Float atribuido a um Integer.", linhas);
					}
				else
					{
					if($3.tipo == INTEGER)
						{
						tabela_simbolos[pos].int_valor = $3.int_valor;
						add_instv("CRVL", $3.int_valor);
						}
					else
						{	
						tabela_simbolos[pos].real_valor = $3.real_valor;
						add_instv("CRVL", $3.real_valor);
						}
					add_instv("ARMZ", pos);
					}
            	}
			}
                |
                IDENT error {adderror(SINTATICO,"Erro na atribuicao.", linhas); yyclearin; yyerrok;}
                |
                REPEAT { current_inst2 = num_inst; } comandos UNTIL condicao {
                        current_inst = add_instv("DSVF", current_inst2+1);
                        }
                |
                BGIN comandos END
                | 
                BGIN comandos error {adderror(SINTATICO,"Problema em 'cmd' BEGIN/END - 'end' esperado.", linhas); yyerrok;}
                | 
                BGIN comandos {adderror(SINTATICO,"Problema em 'cmd' BEGIN/END - 'end' esquecido.", linhas); yyerrok;}
                ;

pfalsa:
                |
                ELSE cmd
                |
                error {yyclearin;} cmd {adderror(SINTATICO,"Problema no IF - 'else' esperado.", linhas); yyerrok;}
                |
                cmd {adderror(SINTATICO,"Problema no IF - 'else' esquecido.", linhas); yyerrok;}
                ;

cmd2:
                ATRIB expressao {
                        $$.tipo = $2.tipo;
                        $$.int_valor = $2.int_valor;
                        $$.real_valor = $2.real_valor;
                        }
                |
                lista_arg {
					$$.tipo = ERRO;
					if(id_proc == -1)
						adderror(SEMANTICO, "Procedimento nao declarado.", linhas);
					else 
						{
						if(p > 0)
							adderror(SEMANTICO, "Quantidade de parametros do procedimento inconsistente.", linhas);
						}
					p = 0;
					}
                ;

condicao:
                expressao relacao expressao {
                        if($1.tipo == INDEFINIDO || $3.tipo == INDEFINIDO)
                                {
                                adderror(SEMANTICO,"Tipo da expressao nao definido.", linhas);
                                $$ = ERRO;
                                }
                        else
                                {
                                if($1.tipo == FLOAT)
                                        temp1 = $1.real_valor;
                                else
                                        temp1 = (1.0)*$1.int_valor;
                                if($3.tipo == FLOAT)
                                        temp2 = $3.real_valor;
                                else
                                        temp2 = (1.0)*$3.int_valor;
                                if($2 == "=")
                                        {
                                        add_instv("CRVL", temp1);
                                        add_instv("CRVL", temp2);
                                        add_inst("CPIG");
                                        if(temp1 == temp2)
                                                $$ = TRUE;
                                        else 
                                                $$ = FALSE;
                                        }
                                else if($2 == "<>")
                                        {
                                        add_instv("CRVL", temp1);
                                        add_instv("CRVL", temp2);
                                        add_inst("CDES");
                                        if(temp1 != temp2)
                                                $$ = TRUE;
                                        else 
                                                $$ = FALSE;
                                        }
                                else if($2 == ">=")
                                        {
                                        add_instv("CRVL", temp1);
                                        add_instv("CRVL", temp2);
                                        add_inst("CMAI");
                                        if(temp1 >= temp2)
                                                $$ = TRUE;
                                        else 
                                                $$ = FALSE;
                                        }
                                else if($2 == "<=")
                                        {
                                        add_instv("CRVL", temp1);
                                        add_instv("CRVL", temp2);
                                        add_inst("CPMI");
                                        if(temp1 <= temp2)
                                                $$ = TRUE;
                                        else 
                                                $$ = FALSE;
                                        }
                                else if($2 == ">")
                                        {
                                        add_instv("CRVL", temp1);
                                        add_instv("CRVL", temp2);
                                        add_inst("CPMA");
                                        if(temp1 > temp2)
                                                $$ = TRUE;
                                        else 
                                                $$ = FALSE;
                                        }
                                else if($2 == "<")
                                        {
                                        add_instv("CRVL", temp1);
                                        add_instv("CRVL", temp2);
                                        add_inst("CPME");
                                        if(temp1 < temp2)
                                                $$ = TRUE;
                                        else 
                                                $$ = FALSE;
                                        }
                                }
                        }
                |
                error relacao {adderror(SINTATICO,"Problema na condicao - Erro na expressao 1.", linhas); yyerrok;} expressao {$$ = ERRO;}
                |
                relacao {adderror(SINTATICO,"Problema na condicao - Expressao 1 esquecida.", linhas); yyerrok;} expressao {$$ = ERRO;}
                |
                expressao error expressao {adderror(SINTATICO,"Problema na condicao - Erro na 'relacao'.", linhas);}
                |
                expressao expressao {adderror(SINTATICO,"Problema na condicao - 'relacao' esquecida.", linhas);}
                |
                expressao relacao error {adderror(SINTATICO,"Problema na condicao - Erro na expressao 2.", linhas); yyclearin; yyerrok;}
                |
                expressao relacao {adderror(SINTATICO,"Problema na condicao - Expressao 2 esquecida.", linhas); yyclearin; yyerrok;}
                ;

relacao:
                IGUAL {$$ = "=";}
                |
                DIFER {$$ = "<>";}
                |
                MAIOR_IGUAL {$$ = ">=";}
                | 
                MENOR_IGUAL {$$ = "<=";}
                | 
                MAIOR {$$ = ">";}
                |
                MENOR {$$ = "<";}
                ;

expressao:                      
                termo outros_termos {
                        if($2.tipo == NULO)
                                {
                                $$.tipo = $1.tipo;
                                $$.int_valor = $1.int_valor;    
                                $$.real_valor = $1.real_valor;
                                }
                        else if($1.tipo == INDEFINIDO || $2.tipo == INDEFINIDO)
                                {
                                adderror(SEMANTICO, "Tipo do ID nao declarado.", linhas);
                                $$.tipo = INDEFINIDO;
                                }
                        else if($1.tipo == FLOAT || $2.tipo == FLOAT)
                                {
                                $$.tipo = FLOAT;
                                if($1.tipo == FLOAT)
                                        add_instv("CRVL", $1.real_valor), temp1 = $1.real_valor;
                                else
                                        add_instv("CRVL", $1.int_valor), temp1 = (float)$1.int_valor;
                                if($2.tipo == FLOAT)
                                        add_instv("CRVL", $2.real_valor), temp2 = $2.real_valor;
                                else
                                        add_instv("CRVL", $2.int_valor), temp2 = (float)$2.int_valor;
                                if ($2.op == '+')
                                        add_inst("SOMA"), $$.real_valor = temp1 + temp2;
                                else 
                                        add_inst("SUBT"), $$.real_valor = temp1 - temp2;
                                }
                        else
                                {
                                $$.tipo = INTEGER;
                                add_instv("CRVL", $1.int_valor);
                                add_instv("CRVL", $2.int_valor);
                                if ($2.op == '+')
                                        add_inst("SOMA"), $$.int_valor = $1.int_valor + $2.int_valor;
                                else 
                                        add_inst("SUBT"), $$.int_valor = $1.int_valor - $2.int_valor;
                                
                                }
                        }
                ;

op_un:                  {
                        $$ = '+';
                        }
                |
                SUB     {
                        $$ = '-';
                        }
                |
                SOMA    {
                        $$ = '+';
                        }
                ;

outros_termos:          {$$.tipo = NULO;}
                |
                op_ad termo outros_termos {
                        if($3.tipo == NULO)
                                {
                                $$.tipo = $2.tipo;
                                $$.int_valor = $2.int_valor;    
                                $$.real_valor = $2.real_valor;
                                $$.op = $1;
                                }
                        else if($2.tipo == INDEFINIDO || $3.tipo == INDEFINIDO)
                                {
                                $$.tipo = INDEFINIDO;
                                }
                        else if($2.tipo == FLOAT || $3.tipo == FLOAT)
                                {
                                $$.tipo = FLOAT;
                                $$.op = $1;
                                if($2.tipo == FLOAT)
                                        add_instv("CRVL", $2.real_valor), temp1 = $2.real_valor;
                                else
                                        add_instv("CRVL", $2.int_valor), temp1 = (float)$2.int_valor;
                                if($3.tipo == FLOAT)
                                        add_instv("CRVL", $3.real_valor), temp2 = $3.real_valor;
                                else
                                        add_instv("CRVL", $3.int_valor), temp2 = (float)$3.int_valor;
                                if ($3.op == '+')
                                        add_inst("SOMA"), $$.real_valor = temp1 + temp2;
                                else 
                                        add_inst("SUBT"), $$.real_valor = temp1 - temp2;
                                }
                        else
                                {
                                $$.tipo = INTEGER;
                                $$.op = $1;
                                add_instv("CRVL", $2.int_valor);
                                add_instv("CRVL", $3.int_valor);
                                if ($3.op == '+')
                                        add_inst("SOMA"), $$.int_valor = $2.int_valor + $3.int_valor;
                                else 
                                        add_inst("SUBT"), $$.int_valor = $2.int_valor - $3.int_valor;           
                                }
                        }
                ;

op_ad:
                SUB     {
                        $$ = '-';
                        }
                |
                SOMA    {
                        $$ = '+';
                        }
                ;

termo:
                op_un fator mais_fatores {
                        if($3.tipo == NULO)
                                {
                                $$.tipo = $2.tipo;
                                if($1 == '-')
                                        {
                                        $$.int_valor = (-1)*$2.int_valor;
                                        $$.real_valor = (-1.0)*$2.real_valor;
                                        }
                                else
                                        {
                                        $$.int_valor = $2.int_valor;
                                        $$.real_valor = $2.real_valor;
                                        }
                                }
                        else if($2.tipo == INDEFINIDO || $3.tipo == INDEFINIDO)
                                {
                                $$.tipo = INDEFINIDO;
                                }
                        else if($2.tipo == FLOAT || $3.tipo == FLOAT)
                                {
                                $$.tipo = FLOAT;
                                if($2.tipo == FLOAT)
                                        {
                                        if($1 == '-')
                                                add_instv("CRVL", (-1.0)*$2.real_valor), temp1 = (-1.0)*$2.real_valor;
                                        else
                                                add_instv("CRVL", $2.real_valor) , temp1 = $2.real_valor;
                                        }
                                else
                                        {
                                        if($1 == '-')
                                                add_instv("CRVL", (-1)*$2.int_valor), temp1 = (float)(-1.0)*$2.int_valor;
                                        else
                                                add_instv("CRVL", $2.int_valor), temp1 = (float)$2.int_valor;
                                        }
                                if($3.tipo == FLOAT)
                                        add_instv("CRVL", $3.real_valor), temp2 = $3.real_valor;
                                else
                                        add_instv("CRVL", $3.int_valor), temp2 = (float)$3.int_valor;
                                if($3.op == '/' && $2.tipo != $3.tipo)
                                        {
                                        adderror(SEMANTICO, "Divisao utilizando numeros inteiros1.", linhas);
                                        $$.tipo = ERRO;
                                        }
                                else 
                                        {
                                        if ($3.op == '/')
                                                if($3.real_valor == 0.0)
                                                        {
                                                        adderror(SEMANTICO, "Divisao por zero.", linhas);
                                                        $$.tipo = ERRO;
                                                        }
                                                else
                                                        add_inst("DIVI"), $$.real_valor = temp1 / temp2;
                                        else 
                                                add_inst("MULT"), $$.real_valor = temp1 * temp2;
                                        }
                                }
                        else
                                {
                                if($3.op == '/')
                                        {
                                        adderror(SEMANTICO, "Divisao utilizando numeros inteiros.", linhas);
                                        $$.tipo = ERRO;
                                        }
                                else
                                        {
                                        $$.tipo = INTEGER;
                                        if($1 == '-')
                                                add_instv("CRVL", (-1)*$2.int_valor), $$.int_valor = (-1)*$2.int_valor * $3.int_valor;
                                        else
                                                add_instv("CRVL", $2.int_valor), $$.int_valor = $2.int_valor * $3.int_valor;
                                        add_instv("CRVL", $3.int_valor);
                                        add_inst("MULT");
                                        }
                                }
                        }
                ;

mais_fatores:           {$$.tipo = NULO;}
                |
                op_mul fator mais_fatores{
                        if($3.tipo == NULO)
                                {
                                $$.tipo = $2.tipo;
                                $$.int_valor = $2.int_valor;    
                                $$.real_valor = $2.real_valor;
                                $$.op = $1;
                                }
                        else if($2.tipo == INDEFINIDO || $3.tipo == INDEFINIDO)
                                {
                                $$.tipo = INDEFINIDO;
                                }
                        else if($2.tipo == FLOAT || $3.tipo == FLOAT)
                                {
                                $$.tipo = FLOAT;
                                $$.op = $1;
                                if($2.tipo == FLOAT)
                                        add_instv("CRVL", $2.real_valor), temp1 = $2.real_valor;
                                else
                                        add_instv("CRVL", $2.int_valor), temp1 = (float)$2.int_valor;
                                if($3.tipo == FLOAT)
                                        add_instv("CRVL", $3.real_valor), temp2 = $3.real_valor;
                                else
                                        add_instv("CRVL", $3.int_valor), temp2 = (float)$3.int_valor;
                                if($3.op == '/' && $2.tipo != $3.tipo)
                                        {
                                        adderror(SEMANTICO, "Divisao utilizando numeros inteiros.", linhas);
                                        $$.tipo = ERRO;
                                        }
                                else 
                                        {
                                        if ($3.op == '/')
                                                if($3.real_valor == 0.0)
                                                        {
                                                        adderror(SEMANTICO, "Divisao por zero.", linhas);
                                                        $$.tipo = ERRO;
                                                        }
                                                else
                                                        add_inst("DIVI"), $$.real_valor = temp1/temp2;
                                        else 
                                                add_inst("MULT"), $$.real_valor = temp1*temp2;
                                        }
                                }
                        else
                                {
                                $$.op = $1;
                                if($3.op == '/')
                                        {
                                        adderror(SEMANTICO, "Divisao utilizando numeros inteiros.", linhas);
                                        $$.tipo = ERRO;
                                        }
                                else
                                        {
                                        $$.tipo = INTEGER;
                                        add_instv("CRVL", $2.int_valor);
                                        add_instv("CRVL", $3.int_valor);
                                        add_inst("MULT");
                                        $$.int_valor = $2.int_valor * $3.int_valor;
                                        }
                                }
                        }
                ;

op_mul:
                DIV     {
                        $$ = '/';
                        }
                |
                MULT    {
                        $$ = '*';
                        }
                ;

fator:
                IDENT   {
                        pos = busca_simb_escopo(tabela_simbolos, $1, hash($1), escopo);
                        if(pos == -1) 
				{
                                adderror(SEMANTICO, "ID nao declarado.", linhas);
                                $$.tipo = ERRO;
                                }
                        else if(tabela_simbolos[pos].tipo == 4) {
                                adderror(SEMANTICO, "ID com tipo reservado.", linhas);
                                $$.tipo = ERRO;
                                }
                        else
                                {
                                $$.tipo = tabela_simbolos[pos].tipo;
                                $$.int_valor = tabela_simbolos[pos].int_valor;
                                $$.real_valor = tabela_simbolos[pos].real_valor;
                                }
                        }
                                
                |
                numero  {
                        $$.tipo = $1.tipo;
                        $$.int_valor = $1.int_valor;
                        $$.real_valor = $1.real_valor;
                        }
                |
                APAR expressao FPAR {
                        $$.tipo = $2.tipo;
                        $$.int_valor = $2.int_valor;    
                        $$.real_valor = $2.real_valor;  
                        }
                ;

numero:
                NUM_INT {
                        $$.tipo = INTEGER; 
                        $$.int_valor = $1;
                        }
                |
                NUM_REAL {
                        $$.tipo = FLOAT; 
                        $$.real_valor = $1;
                        }
                ;

%%
